package com.ly.heart.service.king;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.Gson;
import com.kingdee.bos.webapi.entity.IdentifyInfo;
import com.kingdee.bos.webapi.entity.RepoRet;
import com.kingdee.bos.webapi.sdk.K3CloudApi;
import com.ly.common.exception.CustomException;
import com.ly.common.utils.DateUtils;
import com.ly.common.utils.SecurityUtils;
import com.ly.common.utils.erp.CommonUtil;
import com.ly.common.utils.erp.ConstUtil;
import com.ly.common.utils.erp.KingConstUtil;
import com.ly.heart.domain.KingInvoiceReceivableDetailEntity;
import com.ly.heart.domain.KingInvoiceReceivableEntity;
import com.ly.heart.domain.KingInvoiceReceivableReceiptPlanEntity;
import com.ly.heart.domain.KingOrgEntity;
import com.ly.heart.domain.king.BaseChildBo;
import com.ly.heart.domain.king.payable.FsubHeadFinc;
import com.ly.heart.domain.king.receivable.ReceivableDetail;
import com.ly.heart.domain.king.receivable.ReceivablePlan;
import com.ly.heart.domain.king.receivable.FsubHeadCustomer;
import com.ly.heart.domain.king.receivable.ReceivableBo;
import com.ly.heart.domain.request.KingBaseSingleRequest;
import com.ly.heart.domain.response.KingBaseResponse;
import com.ly.heart.domain.response.KingBaseResponseError;
import com.ly.heart.domain.response.KingBaseResponseSuccessEntity;
import com.ly.heart.service.IKingInvoiceReceivableDetailService;
import com.ly.heart.service.IKingInvoiceReceivableReceiptPlanService;
import com.ly.heart.service.IKingInvoiceReceivableService;
import com.ly.heart.service.IKingOrgService;
import com.ly.heart.util.CurrentUserUtil;
import com.ly.heart.util.KingCommonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: Wuzh
 * @Description:
 * @Date Created in 22:44 2024-07-16
 * @return
 */
@Component
@Slf4j
public class ReceivablePushService {

    @Resource
    private IKingInvoiceReceivableService iKingInvoiceReceivableService;
    @Resource
    private IKingInvoiceReceivableDetailService iKingInvoiceReceivableDetailService;
    @Resource
    private IKingInvoiceReceivableReceiptPlanService iKingInvoiceReceivableReceiptPlanService;
    @Resource
    private IKingOrgService iKingOrgService;

    public void push (String id) {
        KingOrgEntity orgEntity = iKingOrgService.getOne ( new LambdaQueryWrapper<KingOrgEntity> ().eq ( KingOrgEntity :: getOrgId, CurrentUserUtil.getCompanyId () ).eq ( KingOrgEntity :: getIsDisabled, true ) );
        if ( orgEntity == null ) {
            throw new CustomException ( "请先至系统管理中配置金蝶账套！" );
        }
        IdentifyInfo identifyInfo = KingCommonUtil.getIdentifyInfo ( orgEntity );
        K3CloudApi client = new K3CloudApi ( identifyInfo );
        log.info ( "销售开票(应收单)调用金蝶下推 -> {}", id );
        KingInvoiceReceivableEntity kingInvoiceReceivableEntity = iKingInvoiceReceivableService.querySingleById ( id );
        if ( ObjectUtils.isEmpty ( kingInvoiceReceivableEntity ) ) {
            throw new CustomException ( "销售开票(应收单)单据为空！" );
        }
        if ( kingInvoiceReceivableEntity.getIsSend () == KingConstUtil.KING_DATA_IS_SEND_YES ) {
            throw new CustomException ( "该单据已推送金蝶，无需重复推送！" );
        }
        //组装基础对象
        ReceivableBo bo = assembleReceivable ( kingInvoiceReceivableEntity );
        try {
            save ( bo, client );
            submit ( bo, client );
            audit ( bo, client );
            updateSendSuccess ( kingInvoiceReceivableEntity.getId () );
        } catch ( Exception e ) {
            e.printStackTrace ();
            throw new CustomException ( "推送销售开票（应收单）失败！" );
        }
    }

    /**
     * 上推应收单
     * @param bo
     * @param client
     */
    public void save (ReceivableBo bo, K3CloudApi client) throws Exception {
        KingBaseSingleRequest singleRequest = new KingBaseSingleRequest ();
        singleRequest.setModel ( bo );
        String s = JSONObject.toJSONString ( singleRequest );
        log.info ( "销售开票(应收单)转JSON->{}", s );
        String resultJson = client.save ( KingConstUtil.AR_receivable, s );
        //用于记录结果
        Gson gson = new Gson ();
        //对返回结果进行解析和校验
        RepoRet repoRet = gson.fromJson ( resultJson, RepoRet.class );
        KingBaseResponse baseResponse = JSONObject.parseObject ( gson.toJson ( repoRet.getResult ().getResponseStatus () ), KingBaseResponse.class );
        StringBuilder sb = new StringBuilder ();
        if ( baseResponse.getIsSuccess () ) {
            List<KingBaseResponseSuccessEntity> successEntities = baseResponse.getSuccessEntitys ();
            sb.append ( "销售开票(应收单)-编码为：【" );
            successEntities.forEach ( success -> {
                sb.append ( success.getNumber () ).append ( ";" );
            } );
            sb.append ( "】" );
            log.info ( "{} 推送成功", sb );

        } else {
            List<KingBaseResponseError> errors = baseResponse.getErrors ();
            errors.forEach ( err -> {
                sb.append ( err.getMessage () ).append ( ";" );
            } );
            throw new RuntimeException ( "销售开票(应收单)-推送失败：【" + sb + "】" );
        }
    }

    /**
     * 提交应收单到金蝶
     * @param bo
     * @param client
     * @throws Exception
     */
    public void submit (ReceivableBo bo, K3CloudApi client) throws Exception {
        List<String> strings = new ArrayList<> ();
        strings.add ( bo.getFBillNo () );
        bo.setNumbers ( strings );
        String jsonData = JSON.toJSONString ( bo );
        String resultJson = client.submit ( KingConstUtil.AR_receivable, jsonData );
        Gson gson = new Gson ();
        //对返回结果进行解析和校验
        RepoRet repoRet = gson.fromJson ( resultJson, RepoRet.class );
        KingBaseResponse baseResponse = JSONObject.parseObject ( gson.toJson ( repoRet.getResult ().getResponseStatus () ), KingBaseResponse.class );
        StringBuilder sb = new StringBuilder ();
        if ( baseResponse.getIsSuccess () ) {
            //提交成功
            List<KingBaseResponseSuccessEntity> successEntities = baseResponse.getSuccessEntitys ();
            sb.append ( "销售开票(应收单)-编码为：【" );
            successEntities.forEach ( success -> {
                sb.append ( success.getNumber () ).append ( ";" );
            } );
            sb.append ( "】" );
            log.error ( "{} 提交成功", sb );
        } else {
            List<KingBaseResponseError> errors = baseResponse.getErrors ();
            errors.forEach ( err -> {
                sb.append ( err.getMessage () ).append ( ";" );
            } );
            throw new RuntimeException ( "销售开票(应收单)提交失败：【" + sb + "】" );
        }
    }

    /**
     * 审核应收单
     * @param bo
     * @param client
     * @throws Exception
     */
    public void audit (ReceivableBo bo, K3CloudApi client) throws Exception {
        List<String> strings = new ArrayList<> ();
        strings.add ( bo.getFBillNo () );
        bo.setNumbers ( strings );
        String jsonData = JSON.toJSONString ( bo );
        String resultJson = client.audit ( KingConstUtil.AR_receivable, jsonData );
        Gson gson = new Gson ();
        //对返回结果进行解析和校验
        RepoRet repoRet = gson.fromJson ( resultJson, RepoRet.class );
        KingBaseResponse baseResponse = JSONObject.parseObject ( gson.toJson ( repoRet.getResult ().getResponseStatus () ), KingBaseResponse.class );
        StringBuilder sb = new StringBuilder ();
        if ( baseResponse.getIsSuccess () ) {
            //提交成功
            List<KingBaseResponseSuccessEntity> successEntities = baseResponse.getSuccessEntitys ();
            sb.append ( "销售开票(应收单)-编码为：【" );
            successEntities.forEach ( success -> {
                sb.append ( success.getNumber () ).append ( ";" );
            } );
            sb.append ( "】" );
            log.error ( "{} 审核成功", sb );
        } else {
            List<KingBaseResponseError> errors = baseResponse.getErrors ();
            errors.forEach ( err -> {
                sb.append ( err.getMessage () ).append ( ";" );
            } );
            throw new RuntimeException ( "销售开票(应收单)审核失败：【" + sb + "】" );
        }
    }

    /**
     * 修改应收单为已推送状态
     * @param id
     */
    private boolean updateSendSuccess (String id) {
        KingInvoiceReceivableEntity receivableEntity = new KingInvoiceReceivableEntity ();
        receivableEntity.setId ( id );
        receivableEntity.setIsSend ( KingConstUtil.KING_DATA_IS_SEND_YES );
        receivableEntity.setUpdateDate ( DateUtils.getNowDate () );
        receivableEntity.setUpdateUserId ( SecurityUtils.getLoginUser ().getUser ().getUserId () );
        boolean b = iKingInvoiceReceivableService.updateById ( receivableEntity );
        if ( ! b ) {
            throw new CustomException ( "修改推送状态失败！" );
        }
        return b;
    }

    /**
     * 组装基本应收单业务对象
     * @param kingInvoiceReceivableEntity
     * @return
     */
    private ReceivableBo assembleReceivable (KingInvoiceReceivableEntity kingInvoiceReceivableEntity) {
        ReceivableBo bo = new ReceivableBo ();
        //1.基本信息
        //单据编号
        bo.setFBillNo ( kingInvoiceReceivableEntity.getDocNo () );
        //单据类型
        BaseChildBo billType = new BaseChildBo ().setFNumber ( kingInvoiceReceivableEntity.getDocTypeCode () );
        bo.setFBillTypeID ( billType );
        //客户
        BaseChildBo customer = new BaseChildBo ().setFNumber ( kingInvoiceReceivableEntity.getCustomerCode () );
        bo.setFCUSTOMERID ( customer );
        //销售员
        BaseChildBo saleUser = new BaseChildBo ().setFNumber ( kingInvoiceReceivableEntity.getSaleUserCode () );
        bo.setFSALEERID ( saleUser );
        //币别
        BaseChildBo currency = new BaseChildBo ().setFNumber ( kingInvoiceReceivableEntity.getCurrencyCode () );
        bo.setFCURRENCYID ( currency );
        //业务日期
        bo.setFDATE ( CommonUtil.getDateStrFormat ( kingInvoiceReceivableEntity.getBizTime (), "yyyy-MM-dd HH:mm:ss" ) );
        //到期日
        bo.setFENDDATE_H ( CommonUtil.getDateStrFormat ( kingInvoiceReceivableEntity.getDueTime (), "yyyy-MM-dd HH:mm:ss" ) );
        //收款条件
        BaseChildBo payCondition = new BaseChildBo ().setFNumber ( kingInvoiceReceivableEntity.getConditionCode () );
        bo.setFPayConditon ( payCondition );
        //销售部门
        BaseChildBo saleDept = new BaseChildBo ().setFNumber ( kingInvoiceReceivableEntity.getSaleDeptCode () );
        bo.setFSALEDEPTID ( saleDept );
        //立账类型
        bo.setFSetAccountType ( String.valueOf ( kingInvoiceReceivableEntity.getAccountType () ) );
        //按费用项目生成计划
        bo.setFISGENERATEPLANBYCOSTITEM ( kingInvoiceReceivableEntity.getIsFee () );
        //价外税
        bo.setFISPRICEEXCLUDETAX ( kingInvoiceReceivableEntity.getIsExtraPriceTax () );
        //按含税单价录入
        bo.setFISTAX ( kingInvoiceReceivableEntity.getIsIncludeTaxPrice () );
        //备注
        bo.setFAR_Remark ( kingInvoiceReceivableEntity.getRemarks () );

        //2.客户信息
        FsubHeadCustomer FsubHeadSuppiler = new FsubHeadCustomer ();
        BaseChildBo FORDERID = new BaseChildBo ().setFNumber ( kingInvoiceReceivableEntity.getOrCustomerCode () );
        BaseChildBo FTRANSFERID = new BaseChildBo ().setFNumber ( kingInvoiceReceivableEntity.getTrCustomerCode () );
        BaseChildBo FChargeId = new BaseChildBo ().setFNumber ( kingInvoiceReceivableEntity.getChCustomerCode () );
        FsubHeadSuppiler.setFORDERID ( FORDERID ).setFTRANSFERID ( FTRANSFERID ).setFChargeId ( FChargeId );
        bo.setFsubHeadSuppiler ( FsubHeadSuppiler );

        //3.财务
        FsubHeadFinc FsubHeadFinc = new FsubHeadFinc ();
        BaseChildBo FSettleTypeID = new BaseChildBo ().setFNumber ( kingInvoiceReceivableEntity.getSettlementCode () );
        FsubHeadFinc.setFSettleTypeID ( FSettleTypeID ).setFACCNTTIMEJUDGETIME ( CommonUtil.getDateStrFormat ( kingInvoiceReceivableEntity.getDueCalDate (), "yyyy-MM-dd HH:mm:ss" ) );
        bo.setFsubHeadFinc ( FsubHeadFinc );

        //4.明细
        List<ReceivableDetail> ReceivableDetail = assembleDetail ( kingInvoiceReceivableEntity.getId () );
        bo.setFEntityDetail ( ReceivableDetail );

        //5.收款计划明细
        List<ReceivablePlan> ReceivablePlan = assemblePlan ( kingInvoiceReceivableEntity.getId () );
        bo.setFEntityPlan ( ReceivablePlan );
        return bo;
    }

    /**
     * 组装应收单的明细
     * @param receivableId
     * @return
     */
    private List<ReceivableDetail> assembleDetail (String receivableId) {
        List<ReceivableDetail> ReceivableDetail = new ArrayList<> ();
        List<KingInvoiceReceivableDetailEntity> list = iKingInvoiceReceivableDetailService.list ( new QueryWrapper<KingInvoiceReceivableDetailEntity> ().
                eq ( "invoice_receivable_id", receivableId ) );
        list.forEach ( detail -> {
            ReceivableDetail d = new ReceivableDetail ();
            //物料编码
            BaseChildBo FMATERIALID = new BaseChildBo ().setFNumber ( detail.getMaterialCode () );
            d.setFMATERIALID ( FMATERIALID );
            //费用项目编码
            BaseChildBo FCOSTID = new BaseChildBo ().setFNumber ( detail.getFeeCode () );
            d.setFCOSTID ( FCOSTID );
            //计价单位
            BaseChildBo FPRICEUNITID = new BaseChildBo ().setFNumber ( detail.getUnit () );
            d.setFPRICEUNITID ( FPRICEUNITID );
            //单价，含税单价
            d.setFPrice ( detail.getTaxPrice () ).setFTaxPrice ( detail.getTaxPrice () );
            //计价数量
            d.setFPriceQty ( detail.getNum () );
            //税率
            d.setFEntryTaxRate ( detail.getRate () );
            //折扣率
            d.setFEntryDiscountRate ( detail.getDiscountRate () );
            //折扣额
            d.setFDISCOUNTAMOUNTFOR ( detail.getDiscountAmount () );
            //不含税金额
            d.setFNoTaxAmountFor_D ( detail.getNotTaxAmount () );
            //税额
            d.setFTAXAMOUNTFOR_D ( detail.getRateAmount () );
            //价税合计

            //是否赠品
            d.setFIsFree ( detail.getIsFee () );
            //库存单位
            BaseChildBo FStockUnitId = new BaseChildBo ().setFNumber ( detail.getUnit () );
            //销售单位
            BaseChildBo FSalUnitId = new BaseChildBo ().setFNumber ( detail.getUnit () );
            d.setFStockUnitId ( FStockUnitId ).setFSalUnitId ( FSalUnitId );
            //销售数量，销售基本数量，库存基本数量，库存数量=计价数量
            d.setFStockQty ( detail.getNum () ).setFStockBaseQty ( detail.getNum () ).setFSalQty ( detail.getNum () ).setFSalBaseQty ( detail.getNum () );
            //费用承担部门
            BaseChildBo feeDept = new BaseChildBo ().setFNumber ( detail.getFeeBearDeptCode () );
            d.setFCOSTDEPARTMENTID ( feeDept );
            //出库单号
            d.setFOUTSTOCKID ( detail.getInventoryCode () );
            ReceivableDetail.add ( d );
        } );
        return ReceivableDetail;
    }

    /**
     * 组装应收单的收款计划
     * @param receivableId
     * @return
     */
    private List<ReceivablePlan> assemblePlan (String receivableId) {
        List<ReceivablePlan> ReceivablePlan = new ArrayList<> ();
        List<KingInvoiceReceivableReceiptPlanEntity> list = iKingInvoiceReceivableReceiptPlanService.list ( new QueryWrapper<KingInvoiceReceivableReceiptPlanEntity> ().
                eq ( "invoice_receivable_id", receivableId ) );
        list.forEach ( plan -> {
            ReceivablePlan p = new ReceivablePlan ();
            p.setFENDDATE ( CommonUtil.getDateStrFormat ( plan.getDueTime (), "yyyy-MM-dd HH:mm:ss" ) );
            p.setFPAYAMOUNTFOR ( plan.getReceiptAmount () );
            p.setFPAYRATE ( plan.getReceiptRatio () );
            ReceivablePlan.add ( p );
        } );
        return ReceivablePlan;
    }

}
